#include "report.h"

// #define ADDRESS "tcp://192.168.28.37:1883"
#define CLIENTID "ExampleClientSub"
#define DATA_TOPIC "/app/data/down"
#define DATA_TOPICS "/app/data/up"
#define CONTROL_TOPIC "/app/control/down"
#define CONTROL_TOPICS "/app/control/up"
#define MODE_TOPIC "/app/mode/down"
#define MODE_TOPICS "/app/mode/up"
#define PAYLOAD "Hello World!"
#define MODULE "unixs_m0"
#define QOS 1
#define MAXNUM 11
#define TIMEOUT 10000L

int fd_read, fd_write;    //点表文件的文件描述符
char cjson_read[4096];    //读点表存放字符串
char cjson_write[4096];   //写点表存放字符串
cJSON *root_cjson = NULL; //读点表文件根
int qt_work_sign = 0;
int sign = 0;       //结束循环标志位
int send_cjson = 0; //查询发送标志位
void *vp = NULL;    //虚地址
int send_num[MAXNUM] = {0};
char address[64] = "tcp://";
char ip_buf[32];
char port_buf[32];
t_cjson tcjson;
struct std_node *addr_std_node;     //共享内存中结构体数组的地址
static struct unix_param unix_para; //套接字结构体
static struct unix_param unix_para_m0; //套接字结构体
static struct shm_param para;       //共享内存结构体
volatile MQTTClient_deliveryToken deliveredtoken;
MQTTClient client;
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
MQTTClient_message pubmsg = MQTTClient_message_initializer;
MQTTClient_deliveryToken token;

//将点表存放到结构体中--------------------------------------------------------------
void printJson_m0(cJSON *root)
{
    for (int i = 0; i < cJSON_GetArraySize(root); i++)
    {
        cJSON *item = cJSON_GetArrayItem(root, i);
        if (cJSON_Object == item->type)
        {
            for (int j = 0; j < cJSON_GetArraySize(item); j++)
            {
                cJSON *item2 = cJSON_GetArrayItem(item, j);
                switch (j)
                {
                case 0:
                    tcjson.m.dam0[i].key = atoi(cJSON_Print(item2));
                    break;
                case 1:
                    tcjson.m.dam0[i].name = item2->valuestring;
                    break;
                case 2:
                    tcjson.m.dam0[i].type = atoi(cJSON_Print(item2));
                    break;
                }
            }
        }
    }
}

void printJson_modbus(cJSON *root)
{
    for (int i = 0; i < cJSON_GetArraySize(root); i++)
    {
        cJSON *item = cJSON_GetArrayItem(root, i);
        if (cJSON_Object == item->type)
        {
            for (int j = 0; j < cJSON_GetArraySize(item); j++)
            {
                cJSON *item2 = cJSON_GetArrayItem(item, j);
                switch (j)
                {
                case 0:
                    tcjson.mod.damo[i].key = atoi(cJSON_Print(item2));
                    break;
                case 1:
                    tcjson.mod.damo[i].name = item2->valuestring;
                    break;
                case 2:
                    tcjson.mod.damo[i].addr = atoi(cJSON_Print(item2));
                    break;
                case 3:
                    tcjson.mod.damo[i].type = atoi(cJSON_Print(item2));
                    break;
                }
            }
        }
    }
}

void cjson_fill_struct(cJSON *root_cjson)
{
    cJSON *item = NULL;
    cJSON *next = NULL;
    item = cJSON_GetObjectItem(root_cjson, "version");
    tcjson.version = item->valuestring;

    item = cJSON_GetObjectItem(root_cjson, "report");
    next = cJSON_GetObjectItem(item, "type");
    tcjson.rep.type = atoi(cJSON_Print(next));
    next = cJSON_GetObjectItem(item, "period");
    tcjson.rep.period = atoi(cJSON_Print(next));

    item = cJSON_GetObjectItem(root_cjson, "mqtt_server");
    next = cJSON_GetObjectItem(item, "addr");
    tcjson.mqse.addr = next->valuestring;
    next = cJSON_GetObjectItem(item, "port");
    tcjson.mqse.port = atoi(cJSON_Print(next));

    item = cJSON_GetObjectItem(root_cjson, "mb_dev");
    next = cJSON_GetObjectItem(item, "addr");
    tcjson.mbde.addr = next->valuestring;
    next = cJSON_GetObjectItem(item, "port");
    tcjson.mbde.port = atoi(cJSON_Print(next));

    item = cJSON_GetObjectItem(root_cjson, "m0");
    next = cJSON_GetObjectItem(item, "name");
    tcjson.m.name = next->valuestring;
    next = cJSON_GetObjectItem(item, "data");
    printJson_m0(next);

    item = cJSON_GetObjectItem(root_cjson, "modbus");
    next = cJSON_GetObjectItem(item, "name");
    tcjson.mod.name = next->valuestring;
    next = cJSON_GetObjectItem(item, "data");
    printJson_modbus(next);

    LOGD("filling struct is ok");
}
//存放完成------------------------------------------------------------------------------

//由结构体创建cjson---------------------------------------------------------------------
void cjson_create(void)
{
    int i = 0;
    cJSON *root = cJSON_CreateObject();
    cJSON *item = cJSON_CreateObject();
    cJSON *item2 = cJSON_CreateObject();
    cJSON *item3 = cJSON_CreateObject();
    cJSON *item4 = cJSON_CreateObject();
    cJSON *item5 = cJSON_CreateObject();
    cJSON *data = cJSON_CreateArray();
    cJSON *data2 = cJSON_CreateArray();

    cJSON_AddItemToObject(root, "version", cJSON_CreateString(tcjson.version));

    cJSON_AddItemToObject(root, "report", item);
    cJSON_AddItemToObject(item, "type", cJSON_CreateNumber(tcjson.rep.type));
    cJSON_AddItemToObject(item, "period", cJSON_CreateNumber(tcjson.rep.period));

    cJSON_AddItemToObject(root, "mqtt_server", item2);
    cJSON_AddItemToObject(item2, "addr", cJSON_CreateString(tcjson.mqse.addr));
    cJSON_AddItemToObject(item2, "port", cJSON_CreateNumber(tcjson.mqse.port));

    cJSON_AddItemToObject(root, "mb_dev", item3);
    cJSON_AddItemToObject(item3, "addr", cJSON_CreateString(tcjson.mbde.addr));
    cJSON_AddItemToObject(item3, "port", cJSON_CreateNumber(tcjson.mbde.port));

    cJSON_AddItemToObject(root, "m0", item4);
    cJSON_AddItemToObject(item4, "name", cJSON_CreateString(tcjson.m.name));
    cJSON_AddItemToObject(item4, "data", data);
    for (i = 0; i < DATAM0; i++)
    {
        cJSON_AddItemToArray(data, item4 = cJSON_CreateObject());
        cJSON_AddItemToObject(item4, "key", cJSON_CreateNumber(tcjson.m.dam0[i].key));
        cJSON_AddItemToObject(item4, "name", cJSON_CreateString(tcjson.m.dam0[i].name));
        cJSON_AddItemToObject(item4, "type", cJSON_CreateNumber(tcjson.m.dam0[i].type));
    }

    cJSON_AddItemToObject(root, "modbus", item5);
    cJSON_AddItemToObject(item5, "name", cJSON_CreateString(tcjson.mod.name));
    cJSON_AddItemToObject(item5, "data", data2);
    for (i = 0; i < DATAMODBUS; i++)
    {
        cJSON_AddItemToArray(data2, item5 = cJSON_CreateObject());
        cJSON_AddItemToObject(item5, "key", cJSON_CreateNumber(tcjson.mod.damo[i].key));
        cJSON_AddItemToObject(item5, "name", cJSON_CreateString(tcjson.mod.damo[i].name));
        cJSON_AddItemToObject(item5, "addr", cJSON_CreateNumber(tcjson.mod.damo[i].addr));
        cJSON_AddItemToObject(item5, "type", cJSON_CreateNumber(tcjson.mod.damo[i].type));
    }

    strcpy(cjson_write, cJSON_Print(root));
    fd_write = open("./cjson_list.txt", O_WRONLY | O_TRUNC);
    if (fd_write == -1)
    {
        perror("open err\n");
        return;
    }
    // LOGN("HELLO = %s", cjson_write);
    if (write(fd_write, cjson_write, strlen(cjson_write)) < 0)
    {
        LOGE("read err\n");
        return;
    }
    LOGN("write ok");
}
//创建完成--------------------------------------------------------------------------

//将采集到的信息转为cjson--------------------------------------------------------------
void send_cjson_fun(void)
{
    int i = 0;
    cJSON *root = cJSON_CreateObject();
    cJSON *data = cJSON_CreateArray();
    cJSON *item = cJSON_CreateObject();
    char value[64] = {0};

    LOGN("hello");

    cJSON_AddItemToObject(root, "type", cJSON_CreateNumber(1));
    cJSON_AddItemToObject(root, "result", cJSON_CreateNumber(0));

    cJSON_AddItemToObject(root, "data", data);
    for (i = 0; i < MAXNUM; i++)
    {
        if (send_num[i] == 1)
        {
            LOGN("hello");
            cJSON_AddItemToArray(data, item = cJSON_CreateObject());
            cJSON_AddItemToObject(item, "key", cJSON_CreateNumber(addr_std_node[i].key));
            int type = addr_std_node[i].type;
            switch (type)
            {
            case 1:
                sprintf(value, "%d", addr_std_node[i].new_val.b_val);
                cJSON_AddItemToObject(item, "val", cJSON_CreateString(value));
                break;
            case 2:
                sprintf(value, "%d", addr_std_node[i].new_val.i_val);
                cJSON_AddItemToObject(item, "val", cJSON_CreateString(value));
                break;
            case 3:
                sprintf(value, "%f", addr_std_node[i].new_val.f_val);
                cJSON_AddItemToObject(item, "val", cJSON_CreateString(value));
                break;
            }
        }
    }
    LOGN("hello");
    pubmsg.payload = cJSON_Print(root);
    pubmsg.payloadlen = (int)strlen(cJSON_Print(root));
    pubmsg.qos = QOS;
    pubmsg.retained = 0;

    LOGN("hello");

    MQTTClient_publishMessage(client, DATA_TOPICS, &pubmsg, &token);
    // rc = MQTTClient_waitForCompletion(client, token, TIMEOUT);
    printf("Message with delivery token %d delivered\n", token);
}
//-----------------------------------------------------------------------------------

//吧要发送那些设备存入数组-------------------------------------------------------------
void get_send_num(int type)
{
    int i = 0;
    if (type == 1)
    {
        for (i = 0; i < MAXNUM; i++)
        {
            int value_type = addr_std_node[i].type;
            if (value_type == 3)
            {
                if (addr_std_node[i].new_val.f_val == addr_std_node[i].old_val.f_val)
                {
                    send_num[i] = 0;
                }
                else
                {
                    send_num[i] = 1;
                }
            }
            else if (value_type == 2)
            {
                if (addr_std_node[i].new_val.i_val == addr_std_node[i].old_val.i_val)
                {
                    send_num[i] = 0;
                }
                else
                {
                    send_num[i] = 1;
                }
            }
            else if (value_type == 1)
            {
                if (addr_std_node[i].new_val.b_val == addr_std_node[i].old_val.b_val)
                {
                    send_num[i] = 0;
                }
                else
                {
                    send_num[i] = 1;
                }
            }
        }
    }
    else
    {
        for (i = 0; i < MAXNUM; i++)
        {
            send_num[i] = 1;
        }
    }
    LOGN("hello");
}
//-----------------------------------------------------------------------------------

//接收线程--------------------------------------------------------------------------
void *recv_thread(void *arg)
{
    char data[256] = {0};
    while (1)
    {
        if (unix_client_recv(&unix_para, data, 256, NULL) > 0)
        {
            pubmsg.payload = data;
            pubmsg.payloadlen = (int)strlen(data);
            pubmsg.qos = QOS;
            pubmsg.retained = 0;

            LOGN("hello");

            MQTTClient_publishMessage(client, CONTROL_TOPICS, &pubmsg, &token);
            // rc = MQTTClient_waitForCompletion(client, token, TIMEOUT);
            printf("Message with delivery token %d delivered\n", token);
        }
        else if(unix_client_recv(&unix_para_m0, data, 256,NULL) > 0)
        {
            pubmsg.payload = data;
            pubmsg.payloadlen = (int)strlen(data);
            pubmsg.qos = QOS;
            pubmsg.retained = 0;

            LOGN("hello");

            MQTTClient_publishMessage(client, CONTROL_TOPICS, &pubmsg, &token);
            // rc = MQTTClient_waitForCompletion(client, token, TIMEOUT);
            printf("Message with delivery token %d delivered\n", token);
        }
        memset(data,0,256);
    }
}
//接收线程完成-----------------------------------------------------------------------

//发送线程--------------------------------------------------------------------------
// void report_method_0(void)
// {

// }
void *send_thread(void *arg)
{
    int i = 0;
    while (1)
    {
        if (1)
        {
            get_send_num(tcjson.rep.type);
            LOGD("%d", tcjson.rep.type);
            switch (tcjson.rep.type)
            {
            case 0:
            {
                sign = 0;
                LOGD("report_method_0");
                while (!sign)
                {
                    if (send_cjson)
                    {
                        send_cjson_fun();
                        LOGD("report_method_0");
                        send_cjson = 0;
                    }
                    sleep(1);
                }
            }
            break;
            case 1:
            {
                sign = 0;
                LOGD("report_method_1");
                while (!sign)
                {
                    send_cjson_fun();
                    LOGD("report_method_1");
                    sleep(1);
                }
            }
            break;
            case 2:
            {
                sign = 0;
                LOGD("report_method_2");
                while (!sign)
                {
                    send_cjson_fun();
                    LOGD("report_method_2");
                    sleep(tcjson.rep.period);
                }
            }
            break;
            }
        }
        for (i = 0; i < MAXNUM; i++)
        {
            send_num[i] = 0;
        }
    }
}
//----------------------------------------------------------------------------------------

void delivered(void *context, MQTTClient_deliveryToken dt)
{
    printf("Message with token value %d delivery confirmed\n", dt);
    deliveredtoken = dt;
}

int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
    char payloadptr[512] = {0};
    int cjson_object_num = 0;
    cJSON *root = NULL;
    // cJSON *root_create_cjson = NULL;

    LOGD("Message arrived");
    LOGD("     topic: %s", topicName);
    LOGD("   message: ");

    strcpy(payloadptr, message->payload);

    root = cJSON_Parse(payloadptr);
    LOGD("%s", cJSON_Print(root)); //打印Qt发过来的内容
    cjson_object_num = cJSON_GetArraySize(root);
    LOGD("%d", cjson_object_num);

    switch (cjson_object_num)
    {
    case 1:
    {
        cJSON *item = cJSON_GetObjectItem(root, "data");
        cJSON *next = cJSON_GetObjectItem(item, "type");
        tcjson.rep.type = atoi(cJSON_Print(next));
        next = cJSON_GetObjectItem(item, "period");
        tcjson.rep.period = atoi(cJSON_Print(next));
        cjson_create();
        qt_work_sign = 1;
        sign = 1;
    }
    break;
    case 2:
    {
        cJSON *item = cJSON_GetObjectItem(root, "data");
        cJSON *next = cJSON_GetObjectItem(item, "key");
        int key = atoi(cJSON_Print(next));
        for (int i = 0; i < MAXNUM; i++)
        {
            if (key == addr_std_node[i].key)
            {
                if (addr_std_node[i].dev_type == 0)
                {
                    LOGD("hello m0 %d", key);
                    unix_client_send(&unix_para_m0, payloadptr, 512);
                }
                else if (addr_std_node[i].dev_type == 1)
                {
                    unix_client_send(&unix_para, payloadptr, 512);
                }
                break;
            }
        }
    }
    break;
    case 3:
    {
        if (tcjson.rep.type == 0)
        {
            send_cjson = 1;
        }
    }
    break;
    }

    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
    return 1;
}

void connlost(void *context, char *cause)
{
    printf("\nConnection lost\n");
    printf("     cause: %s\n", cause);
}

int main(int argc, char *argv[])
{
    int rc;
    int ret = -1;
    pthread_t send_mqtt_tid;
    pthread_t recv_device_tid;
    // int ch;
    // char buf[32] = {0};
    // MQTTClient client;
    // MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    // MQTTClient_message pubmsg = MQTTClient_message_initializer;
    // MQTTClient_deliveryToken token;
    // unix_init_server(&unix_para, MODULE);
    unix_init_client(&unix_para_m0, "m0_unixc_test", MODULE);
    unix_init_client(&unix_para, "unixc_test", "unixs_modbus"); //套接字创建连接
    set_dbg_level(APP_DEBUG);                                   // log直接送往当前终端时，通过代码设置打印级别

    //读点表文件，填充结构体--------------------------------------------------------------------
    fd_read = open("./cjson_list.txt", O_RDONLY);
    if (fd_read == -1)
    {
        perror("open err\n");
        return -1;
    }

    if (read(fd_read, cjson_read, 4096) < 0)
    {
        LOGE("read err\n");
        return -1;
    }
    root_cjson = cJSON_Parse(cjson_read);
    // LOGD("%s", cJSON_Print(root_cjson));
    cjson_fill_struct(root_cjson);
    //完成结构体填充-------------------------------------------------------------------------

    //填充ip--------------------------------------------------------------------------------
    strcpy(ip_buf, tcjson.mqse.addr);
    strcat(address, ip_buf);
    char add[1] = ":";
    strcat(address, add);
    sprintf(port_buf, "%d", tcjson.mqse.port);
    strcat(address, port_buf);
    LOGN("%s", address);
    //-------------------------------------------------------------------------------------

    // mqtt连接初始化-------------------------------------------------------------------------
    MQTTClient_create(&client, address, CLIENTID,
                      MQTTCLIENT_PERSISTENCE_NONE, NULL);
    conn_opts.keepAliveInterval = 20;
    conn_opts.cleansession = 1;
    MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered);

    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to connect, return code %d\n", rc);
        exit(EXIT_FAILURE);
    }
    MQTTClient_subscribe(client, DATA_TOPIC, QOS);
    LOGN("Subscribing to topic %s\nfor client %s using QoS%d\n\n"
         "Press Q<Enter> to quit\n\n",
         DATA_TOPIC, CLIENTID, QOS);
    MQTTClient_subscribe(client, CONTROL_TOPIC, QOS);
    LOGN("Subscribing to topic %s\nfor client %s using QoS%d\n\n"
         "Press Q<Enter> to quit\n\n",
         CONTROL_TOPIC, CLIENTID, QOS);
    MQTTClient_subscribe(client, MODE_TOPIC, QOS);
    LOGN("Subscribing to topic %s\nfor client %s using QoS%d\n\n"
         "Press Q<Enter> to quit\n\n",
         MODE_TOPIC, CLIENTID, QOS);
    // mqtt连接初始化完成---------------------------------------------------------------------

    //创建共享内存----------------------------------------------------------------------------
    ret = shm_init(&para, "shm_test", sizeof(struct std_node) * 11);
    if (ret < 0)
    {
        return -1;
    }
    vp = shm_getaddr(&para);
    if (vp == NULL)
    {
        return -1;
    }
    addr_std_node = vp;
    LOGD("HELLO");
    //创建共享内存完成------------------------------------------------------------------------

    //创建发送线程----------------------------------------------------------------------------
    if (pthread_create(&send_mqtt_tid, NULL, send_thread, NULL) != 0)
    {
        perror("pthread send_create error.");
        return -1;
    }
    LOGD("HELLO");
    //创建发送线程完成------------------------------------------------------------------------

    //创建接收设备信息线程--------------------------------------------------------------------
    if (pthread_create(&recv_device_tid, NULL, recv_thread, NULL) != 0)
    {
        perror("pthread recv_create error.");
        return -1;
    }
    //创建接收设备信息线程完成-----------------------------------------------------------------

    do
    {
        // cJSON *root = cJSON_CreateObject();
        // cJSON_AddItemToObject(root, "name", cJSON_CreateString("fengshuangqing"));
        // cJSON_AddItemToObject(root, "age", cJSON_CreateNumber(22));
        // scanf("%[^\n]", buf);
        // getchar();
        // cJSON_AddItemToObject(root, "msg", cJSON_CreateString(buf));

        // pubmsg.payload = cJSON_Print(root);
        // pubmsg.payloadlen = (int)strlen(cJSON_Print(root));
        // pubmsg.qos = QOS;
        // pubmsg.retained = 0;

        // MQTTClient_publishMessage(client, TOPICS, &pubmsg, &token);
        // rc = MQTTClient_waitForCompletion(client, token, TIMEOUT);
        // printf("Message with delivery token %d delivered\n", token);

        // memset(buf, 0, 32);
    } while (1);

    MQTTClient_unsubscribe(client, DATA_TOPIC);
    MQTTClient_unsubscribe(client, CONTROL_TOPIC);
    MQTTClient_unsubscribe(client, MODE_TOPIC);
    MQTTClient_disconnect(client, 10000);
    MQTTClient_destroy(&client);
    pthread_join(send_mqtt_tid, NULL);
    memset(vp, 0, sizeof(struct std_node) * 11);
    shm_del(&para);
    close(fd_read);
    close(fd_write);
    return rc;
}